package com.quick.develop.flowable.framework.cmd;

import com.quick.develop.flowable.domain.model.BpmModelUpdateReqVO;
import com.quick.develop.flowable.framework.convert.model.BpmModelConvert;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;

/**
 * @author junyuan.liu
 * @description: 修改模型，如果修改模型名称，考虑修改以下信息
 *                  1、act_re_model 模型表 名称
 *                  2、流程图xml名称，是否有部署过？
 * @date 2022/8/22 11:29
 */
@Slf4j
public class UpdateModelInfoCmd implements Command<Void>, Serializable {
    private static final long serialVersionUID = 6318490891730532901L;
    
    protected Model model;
    protected BpmModelUpdateReqVO updateReqVO;
    
    public UpdateModelInfoCmd(Model model, BpmModelUpdateReqVO updateReqVO) {
        this.model = model;
        this.updateReqVO = updateReqVO;
    }
    

    @Override
    public Void execute(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        RepositoryService repositoryService = processEngineConfiguration.getRepositoryService();
        // 更新 名称
        if (!Objects.equals(model.getName(), updateReqVO.getName()) ) {
            updateXml(commandContext, repositoryService);
        }
        // 类别不同 更新
        if (!Objects.equals(model.getCategory(), updateReqVO.getCategory())) {
            updateCategory(commandContext);
        }
        BpmModelConvert.INSTANCE.copy(model, updateReqVO);
        repositoryService.saveModel(model);
        
        return null;
    }
    
    protected void updateCategory(CommandContext commandContext) {
        RepositoryService repositoryService = CommandContextUtil.getProcessEngineConfiguration(commandContext).getRepositoryService();
        List<Deployment> deploymentList = repositoryService.createDeploymentQuery().deploymentKey(model.getKey()).list();
        List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery().processDefinitionKey(model.getKey()).list();
        deploymentList.forEach(l -> {
            repositoryService.setDeploymentCategory(l.getId(), updateReqVO.getCategory());
        });
        definitionList.forEach(l -> {
            repositoryService.setProcessDefinitionCategory(l.getId(), updateReqVO.getCategory());
        });

    }
    
    
    protected void updateXml(CommandContext commandContext, RepositoryService repositoryService) {
        byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId());
        if (Objects.isNull(bpmnBytes)) {
            return;
        }
        
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        ByteArrayOutputStream outputStream = null;
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(new ByteArrayInputStream(bpmnBytes));
            NodeList list = doc.getElementsByTagName("bpmn2:process");
            for (int i = 0; i < list.getLength(); i++) {
                Element item = (Element) list.item(i);
                String name = item.getAttribute("name");
                if (Objects.equals(name, model.getName()) ) {
                    item.setAttribute("name", updateReqVO.getName());
                }
            }

            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty("encoding", "UTF-8");
            outputStream = new ByteArrayOutputStream();
            transformer.transform(new DOMSource(doc), new StreamResult(outputStream));
            repositoryService.addModelEditorSource(model.getId(), outputStream.toByteArray());
            
        }catch (Exception e) {
            log.error("更新流程图名称失败：{}", e.getMessage());
            e.printStackTrace();
        }finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        
        
        
    }
}
